// (C) 2022 Intel Corporation. All rights reserved.
// Your use of Intel Corporation's design tools, logic functions and other 
// software and tools, and its AMPP partner logic functions, and any output 
// files from any of the foregoing (including device programming or simulation 
// files), and any associated documentation or information are expressly subject 
// to the terms and conditions of the Intel Program License Subscription 
// Agreement, Intel FPGA IP License Agreement, or other applicable 
// license agreement, including, without limitation, that your use is for the 
// sole purpose of programming logic devices manufactured by Intel and sold by 
// Intel or its authorized distributors.  Please refer to the applicable 
// agreement for further details.

module avmm_mux_2Masters_To_5Slaves #(
    parameter SLV1_ADDR_LOW  = 32'h0000,
    parameter SLV1_ADDR_High = 32'h00FF,
    parameter SLV2_ADDR_LOW  = 32'h0100,
    parameter SLV2_ADDR_High = 32'h01FF,
    parameter SLV3_ADDR_LOW  = 32'h0200,
    parameter SLV3_ADDR_High = 32'h02FF,
    parameter SLV4_ADDR_LOW  = 32'h0300,
    parameter SLV4_ADDR_High = 32'h03FF,
    parameter SLV5_ADDR_LOW  = 32'h4000,
    parameter SLV5_ADDR_High = 32'hFFFF
)(
    input         clk,           
    input         rst_n,
    //AVMM_Single_Master1
    input      [31:0] mst1_address,
    input             mst1_write,
    input      [31:0] mst1_writedata,          
    input             mst1_read,     
    output reg [31:0] mst1_readdata,      
    output            mst1_readdatavalid, 
    output            mst1_waitrequest,           
    input      [ 3:0] mst1_byteenable,

    input      [31:0] mst2_address,
    input             mst2_write,
    input      [31:0] mst2_writedata,    
    input             mst2_read,     
    output reg [31:0] mst2_readdata,     
    output            mst2_readdatavalid,
    output            mst2_waitrequest,  
    input      [ 3:0] mst2_byteenable,


    output            invalid_access,	 
    //AVMM_Slave_1
    output reg [31:0] slv1_address,
    output reg        slv1_write,
    output     [31:0] slv1_writedata,          
    output reg        slv1_read,       
    input      [31:0] slv1_readdata,      
    input             slv1_readdatavalid, 
    input             slv1_waitrequest,            
    output     [ 3:0] slv1_byteenable,
	 input             invalid_access_slv1,
    //AVMM_Slave_2
    output reg [31:0] slv2_address,
    output reg        slv2_write,
    output     [31:0] slv2_writedata,          
    output reg        slv2_read,       
    input      [31:0] slv2_readdata,      
    input             slv2_readdatavalid, 
    input             slv2_waitrequest,            
    output     [ 3:0] slv2_byteenable,
	 input             invalid_access_slv2,
    //AVMM_Slave_3
    output reg [31:0] slv3_address,
    output reg        slv3_write,
    output     [31:0] slv3_writedata,          
    output reg        slv3_read,       
    input      [31:0] slv3_readdata,      
    input             slv3_readdatavalid, 
    input             slv3_waitrequest,            
    output     [ 3:0] slv3_byteenable,
	 input             invalid_access_slv3,
    //AVMM_Slave_4
    output reg [31:0] slv4_address,
    output reg        slv4_write,
    output     [31:0] slv4_writedata,          
    output reg        slv4_read,       
    input      [31:0] slv4_readdata,      
    input             slv4_readdatavalid, 
    input             slv4_waitrequest,            
    output     [ 3:0] slv4_byteenable,
    input             invalid_access_slv4,

    output reg [31:0] slv5_address,
    output reg        slv5_write,
    output     [31:0] slv5_writedata,          
    output reg        slv5_read,       
    input      [31:0] slv5_readdata,      
    input             slv5_readdatavalid, 
    input             slv5_waitrequest,            
    output     [ 3:0] slv5_byteenable,
    input             invalid_access_slv5,


    
    //status_reg log, only exist on SCM FPGA
    output     [ 3:0] status_reg,             //log error info into general CSR
    input      [ 3:0] status_reg_mm   	       //LVDS_MM error info
);





wire     [31:0] mst_address;
wire            mst_write;
wire     [31:0] mst_writedata;    
wire            mst_read;     
wire   [31:0]   mst_readdata;     
wire            mst_readdatavalid;
wire            mst_waitrequest;  
wire     [ 3:0] mst_byteenable;





reg       invalid_access_rsv;
reg       invalid_access_latch;
reg       mst_read_d;

reg [4:0] cs;
wire cs_mst;
reg [4:0] cs_latch;

//pass input writedata & byteenable signals from master port to each slave ports directly.
assign slv1_writedata  = mst_writedata;
assign slv1_byteenable = 4'hf;

assign slv2_writedata  = mst_writedata;
assign slv2_byteenable = 4'hf;

assign slv3_writedata  = mst_writedata;
assign slv3_byteenable = 4'hf;

assign slv4_writedata  = mst_writedata;
assign slv4_byteenable = 4'hf;

assign slv5_writedata  = mst_writedata;
assign slv5_byteenable = 4'hf;


assign invalid_access = invalid_access_slv1 || invalid_access_slv2 || invalid_access_slv3 || invalid_access_slv4 ||invalid_access_slv5 || invalid_access_rsv;


 always @(*) begin
 if(mst1_read ||mst1_write) begin
    cs_mst=1'b0;
 end

  else if(mst2_read ||mst2_write) begin
    cs_mst=1'b1;

 end
end 
always @ (*) begin
    case ( cs_mst )
            1'b0    : begin
            
                         mst_address          =  mst1_address          ;
                         mst_write            =  mst1_write            ;
                         mst_writedata        =  mst1_writedata        ;  
                         mst_read             =  mst1_read             ;  
                         mst_byteenable       =  mst1_byteenable       ;
                         mst1_readdata        =  mst_readdata          ;  
                         mst1_readdatavalid   =  mst_readdatavalid     ;
                         mst1_waitrequest     = mst_waitrequest     ;  
                         end
    
            1'b1    :    begin
                         mst_address          =mst2_address          ;
                         mst_write            =mst2_write            ;
                         mst_writedata        =mst2_writedata        ;  
                         mst_read             =mst2_read             ;  
                         mst_byteenable       =mst2_byteenable       ;
                         mst2_readdata        =mst_readdata          ;  
                         mst2_readdatavalid   =mst_readdatavalid     ;
                         mst2_waitrequest     =mst_waitrequest       ;  

                        end

       default : begin 
                 mst_address                ='b0;
                 mst_write                  ='b0;
                 mst_writedata              ='b0;
                 mst_read                   ='b0;
                 mst_byteenable             ='b0;
                 mst_readdata               ='b0;
                 mst_readdatavalid          ='b0;
                 mst_waitrequest            ='b0;


                 mst1_readdata              ='b0;
                 mst1_readdatavalid         ='b0;
                 mst1_waitrequest           ='b0;

                 mst2_readdata              ='b0;
                 mst2_readdatavalid         ='b0;
                 mst2_waitrequest           ='b0;


                 
                 end  

    endcase
end 



//////////////////////////////////////

always @ (*) begin
    if( mst_address >= SLV1_ADDR_LOW && mst_address <= SLV1_ADDR_High ) begin
        cs                    = 5'b00001;
		  invalid_access_rsv    = 1'b0;
    end else if ( mst_address >= SLV2_ADDR_LOW && mst_address <= SLV2_ADDR_High ) begin
        cs                    = 5'b00010;
		  invalid_access_rsv    = 1'b0;
    end else if ( mst_address >= SLV3_ADDR_LOW && mst_address <= SLV3_ADDR_High ) begin
        cs                    = 5'b00100;
		  invalid_access_rsv    = 1'b0;
    end else if ( mst_address >= SLV4_ADDR_LOW && mst_address <= SLV4_ADDR_High ) begin
        cs                    = 5'b01000;
        invalid_access_rsv    = 1'b0;        
    end else if ( mst_address >= SLV5_ADDR_LOW && mst_address <= SLV5_ADDR_High ) begin
        cs                    = 5'b10000;
        invalid_access_rsv    = 1'b0;     
        
    
    end else begin
        cs                    = 5'b0;
		  invalid_access_rsv    = 1'b1;
    end  
end

always @ ( posedge clk) begin
    if ( !rst_n ) begin
        cs_latch <= 5'b0;
    end else begin
        if ( mst_read || mst_write ) begin
            cs_latch <= cs;
        end else begin
            cs_latch <= cs_latch;
        end
    end
end

//latch invalid_access for next read/write command
always @ (posedge clk or negedge rst_n) begin
   if (!rst_n) begin
	   invalid_access_latch    <= 1'b0;
	end
	else if ((mst_read || mst_write) && invalid_access) begin
	   invalid_access_latch    <= 1'b1;
	end
	else if ((mst_read || mst_write) && !invalid_access) begin
	   invalid_access_latch    <= 1'b0;
	end
end

//delay read for one clock
always @ (posedge clk or negedge rst_n) begin
   if (!rst_n) begin
	   mst_read_d          <= 1'b0;
	end
	else begin
	   mst_read_d          <= mst_read;
	end
end

//log status reg
always @ (posedge clk or negedge rst_n) begin
   if (!rst_n) begin
	   status_reg    <= 4'h0;
	end
	else begin
	   if (cs_latch == 5'b10000) begin
		   status_reg          <= status_reg_mm;
		end
		else if (cs_latch == 5'b0 || cs_latch == 5'b1 || cs_latch == 5'b10 || cs_latch == 5'b100 ||cs_latch == 5'b1000 ||cs_latch == 5'b10000)begin
		   if (invalid_access_latch) begin
			   status_reg       <= 4'h1;
			end
			else begin
			   status_reg       <= 4'h0;
			end
		end
	end
end

//pass slave readdata to mast according to address range.
always @ (*) begin
    case ( cs_latch )
        5'b1     : mst_readdata  = slv1_readdata;
        5'b10    : mst_readdata  = slv2_readdata;
        5'b100   : mst_readdata  = slv3_readdata;
        5'b1000  : mst_readdata  = slv4_readdata;
        5'b10000 : mst_readdata  = slv5_readdata;
        default  : mst_readdata  = 32'hFFFF_FFFF;
    endcase
end 

//pass relative addr from mst to slv
always @ (*) begin
    case ( cs )
        5'b00001   : begin
                     slv1_address  = mst_address - SLV1_ADDR_LOW; // Use Relative addr to selected slave device
                     slv2_address  = 'b0;
                     slv3_address  = 'b0;
                     slv4_address  = 'b0;
                     slv5_address  = 'b0;
                  end
        5'b00010  : begin
                     slv2_address  = mst_address - SLV2_ADDR_LOW; // Use Relative addr to selected slave device
                     slv1_address  = 'b0;
                     slv3_address  = 'b0;
                     slv4_address  = 'b0;
                     slv5_address  = 'b0;
                  end   
        5'b00100 : begin
                     slv3_address  = mst_address - SLV3_ADDR_LOW; // Use Relative addr to selected slave device
                     slv2_address  = 'b0;
                     slv1_address  = 'b0;
                     slv4_address  = 'b0;
                     slv5_address  = 'b0;
                  end
        5'b01000 : begin
                     slv4_address  = mst_address - SLV4_ADDR_LOW; // Use Relative addr to selected slave device
                     slv2_address  = 'b0;
                     slv3_address  = 'b0;
                     slv1_address  = 'b0;
                     slv5_address  = 'b0;
                  end   
                  
        5'b10000 : begin
                    slv5_address  = mst_address - SLV5_ADDR_LOW; // Use Relative addr to selected slave device
                    slv2_address  = 'b0;
                    slv3_address  = 'b0;
                    slv1_address  = 'b0;
                    slv4_address  = 'b0;
                 end                               

        default : begin
	                  slv1_address  = 'b0;
                     slv2_address  = 'b0;
                     slv3_address  = 'b0;
                     slv4_address  = 'b0;
                     slv5_address  = 'b0;
				  end
    endcase
end 

//pass mst_write to slave according to cs
always @ (*) begin
    case ( cs )
        5'b00001   : begin
                     slv1_write  = mst_write;
                     slv2_write  = 'b0;
                     slv3_write  = 'b0;
                     slv4_write  = 'b0;
                     slv5_write  = 'b0;
                  end
        5'b00010  : begin
                     slv2_write  = mst_write;
                     slv1_write  = 'b0;
                     slv3_write  = 'b0;
                     slv4_write  = 'b0;
                     slv5_write  = 'b0;
                  end   
        5'b00100 : begin
                     slv3_write  = mst_write;
                     slv1_write  = 'b0;
                     slv2_write  = 'b0;
                     slv4_write  = 'b0;
                     slv5_write  = 'b0;
                  end
        5'b01000 : begin
                     slv4_write  = mst_write;
                     slv1_write  = 'b0;
                     slv2_write  = 'b0;
                     slv3_write  = 'b0;
                     slv5_write  = 'b0;
                  end    
        5'b10000 : begin
                    slv5_write  = mst_write;
                    slv1_write  = 'b0;
                    slv2_write  = 'b0;
                    slv3_write  = 'b0;
                    slv4_write  = 'b0;
                 end                  
                  
        default : begin
	                  slv1_write  = 'b0;
                     slv2_write  = 'b0;
                     slv3_write  = 'b0;
                     slv4_write  = 'b0;
                     slv5_write  = 'b0;
				  end
    endcase
end 

//pass mst_read to slave according to cs
always @ (*) begin
    case ( cs )
        5'b00001   : begin
                     slv1_read  = mst_read;
                     slv2_read  = 'b0;
                     slv3_read  = 'b0;
                     slv4_read  = 'b0;
                     slv5_read  = 'b0;
                  end
        5'b00010  : begin
                     slv2_read  = mst_read;
                     slv1_read  = 'b0;
                     slv3_read  = 'b0;
                     slv4_read  = 'b0;
                     slv5_read  = 'b0;
                  end   
        5'b00100 : begin
                     slv3_read  = mst_read;
                     slv1_read  = 'b0;
                     slv2_read  = 'b0;
                     slv4_read  = 'b0;
                     slv5_read  = 'b0;
                  end
        5'b01000 : begin
                     slv4_read  = mst_read;
                     slv1_read  = 'b0;
                     slv2_read  = 'b0;
                     slv3_read  = 'b0;
                     slv5_read  = 'b0;
                  end  
        
        5'b10000 : begin
                    slv5_read  = mst_read;
                    slv1_read  = 'b0;
                    slv2_read  = 'b0;
                    slv3_read  = 'b0;
                    slv4_read  = 'b0;
                 end 
        default : begin
	                 slv1_read  = 'b0;
                     slv2_read  = 'b0;
                     slv3_read  = 'b0;
                     slv4_read  = 'b0;
                     slv5_read  = 'b0;
				  end
    endcase
end 

assign mst_waitrequest   = slv1_waitrequest || slv2_waitrequest || slv3_waitrequest || slv4_waitrequest|| slv5_waitrequest;
assign mst_readdatavalid = (mst_read_d && invalid_access_latch) ? 1'b1: (slv1_readdatavalid || slv2_readdatavalid ||slv3_readdatavalid ||slv4_readdatavalid||slv5_readdatavalid);  //For SCM side to feedback valid data to BMC master

endmodule
